package com.xiaobaibai.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.xiaobaibai.common.OrderCommon;
import com.xiaobaibai.common.OrderEnum;
import com.xiaobaibai.entity.*;
import com.xiaobaibai.response.ResponseFormat;
import com.xiaobaibai.service.*;
import com.xiaobaibai.threadPool.MyThreadPoolUnit;
import com.xiaobaibai.units.pay.BigDecimalUtil;
import com.xiaobaibai.units.Last7DaysUtil;
import com.xiaobaibai.units.OrderWXNewsUnit;
import com.xiaobaibai.units.SecurityUnit;
import com.xiaobaibai.vo.CreateOrderVo;
import com.xiaobaibai.vo.OrderItemVo;
import com.xiaobaibai.vo.OrderListVo;
import com.xiaobaibai.websocket.WebSocketServer;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@RestController
@Api(tags = "订单接口")
@RequestMapping("/order")
@CrossOrigin
@Slf4j
public class OrderController {

    @Autowired
    private IOrderService orderService;

    @Autowired
    private IOrderItemService orderItemService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private MyThreadPoolUnit threadPoolUnit;

    @Autowired
    private IProductService productService;

    @Autowired
    private IUserInfoService userInfoService;

    @Autowired
    private IUserIntegralDetailService userIntegralDetailService;

    @Autowired
    private OrderWXNewsUnit orderWXNewsUnit;

    /**
     * 加锁的目的是为了用户同时操作确认收货和取消订单
     * 这种类似的情况
     */

    @PostMapping("/create")
    @ApiOperation("创建订单")
    public ResponseFormat createOrder(@Validated @RequestBody CreateOrderVo createOrderVo){
        long start=System.currentTimeMillis();
        Integer userId= SecurityUnit.getUserId();
        Boolean flag = stringRedisTemplate.hasKey(OrderCommon.doOrderLock + userId);
        if(flag)//存在订单锁
            return ResponseFormat.failure("订单操作频繁,请15秒后再试");
        String orderId=null;
        try {
            //来个redis锁,一次只能下一次单
            stringRedisTemplate.opsForValue()
                    .set(OrderCommon.doOrderLock+userId,"1",15, TimeUnit.SECONDS);
            //本来要返回一个消费金额,但是不需要了
            orderId = orderService.createOrder(createOrderVo, userId);
        }catch (Exception e){
            log.error(e.getMessage());
            return ResponseFormat.failure(e.getMessage());
        }finally {
            //取消订单锁
            stringRedisTemplate.delete(OrderCommon.doOrderLock+userId);
        }
        //下面异步操作->加入最近订单
        threadPoolUnit.recentOrder(createOrderVo.getList().get(0).getProductId(),userId);
        try {
            if(createOrderVo.getFaceToFace()) {
                WebSocketServer.sendNewOrderTip();//给老板发送订单通知
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("总耗时:"+(System.currentTimeMillis()-start)+"毫秒");
        return ResponseFormat.ok("下单成功",orderId);//返回订单id,给下单
    }

    @GetMapping("/list")
    @ApiOperation("查看自己的订单")
    public ResponseFormat getMyOrderList(@RequestParam(value = "pageNum",required = false,defaultValue = "1")
                                                     Integer pageNum){
        Integer userId=SecurityUnit.getUserId();
        pageNum-=1;//自减一适配
        //每次查询个5条
        List<Order> list= orderService.getMyOrderList(pageNum, 5, userId);
        if(list.size()==0)
            return ResponseFormat.ok("获取订单列表成功",list);
        List<OrderListVo> orderListVos = this.getOrderListVo2(list);
        return ResponseFormat.ok("获取订单列表成功",orderListVos);
    }

    @GetMapping("/detail")
    @ApiOperation("订单详细")
    public ResponseFormat getOrderDetail(@RequestParam(value = "orderId")String orderId){
        Integer userId=SecurityUnit.getUserId();
        Order order = orderService.getById(orderId);
        if(!userId.equals(order.getUserId()))
            return ResponseFormat.failure("仅可查看自己的订单");
        QueryWrapper<OrderItem> q1=new QueryWrapper<>();
        q1.eq("order_id",orderId);
        List<OrderItem> orderItemList = orderItemService.list(q1);
        //转为orderItemVo
        List<OrderItemVo>  orderItemVoList=new ArrayList<>();
        orderItemList.forEach(o->{
            Product product = productService.getProductById(o.getProductId());
            OrderItemVo orderItemVo = OrderItemVo.convertOrderItemVo(product, o);
            orderItemVoList.add(orderItemVo);
        });
        Map<String,Object> map=new HashMap<>();
        map.put("order",order);
        map.put("productList",orderItemVoList);
        return ResponseFormat.ok("获取订单详细成功",map);
    }

    @GetMapping("/waitPayOrder")
    @ApiOperation("获取待支付订单接口")
    public ResponseFormat getWaitPayOrder(){
        Integer userId = SecurityUnit.getUserId();
        List<OrderListVo> orderListVos = getOrderListVo(OrderEnum.NOPAY, userId);
        return ResponseFormat.ok("获取待支付订单成功",orderListVos);
    }

    @GetMapping("/waitAcceptOrder")
    @ApiOperation("获取待收货订单接口")
    public ResponseFormat getWaitAcceptOrder(){
        Integer userId = SecurityUnit.getUserId();
        List<OrderListVo> orderListVos1 = getOrderListVo(OrderEnum.FACETO, userId);
        List<OrderListVo> orderListVos2 = getOrderListVo(OrderEnum.ING, userId);
        orderListVos1.addAll(orderListVos2);//添加进一个
        return ResponseFormat.ok("获取待支付订单列表成功",orderListVos1);
    }

    @GetMapping("/waitEvaluationOrder")
    @ApiOperation("获取待评价订单接口")
    public ResponseFormat getWaitEvaluationOrder(){
        Integer userId = SecurityUnit.getUserId();
        List<String> range = stringRedisTemplate.opsForList().range(OrderCommon.waitEvaluationOrder+userId, 0, -1);
        if(range==null||range.size()==0)
            return ResponseFormat.ok("没有待评价订单",new ArrayList<>());
        QueryWrapper<Order> q1=new QueryWrapper<>();
        q1.in("order_id",range);
        List<Order> list=orderService.list(q1);
        List<OrderListVo> orderListVo2 = getOrderListVo2(list);
        return ResponseFormat.ok("获取待评价订单列表成功",orderListVo2);
    }

    @GetMapping("/waitCancel")
    @ApiOperation("查看正在取消中/退款中的订单(货到付款在送的期间就是取消订单,微信支付订单在送的期间就是退款)")
    public ResponseFormat waitCancel(){
        Integer userId = SecurityUnit.getUserId();
        List<OrderListVo> orderListVo = this.getOrderListVo(OrderEnum.CANCELING, userId);
        List<OrderListVo> orderListVo1 = this.getOrderListVo(OrderEnum.REFUNDING, userId);
        orderListVo.addAll(orderListVo1);
        return ResponseFormat.ok("获取正在取消中的订单成功",orderListVo);
    }

    @GetMapping("/confirmGoods")
    @ApiOperation("确认收货")
    public ResponseFormat confirmGoods(@RequestParam(value = "orderId")String orderId){

        Integer userId=SecurityUnit.getUserId();
        //让老板的点击完成权限交给顾客
        QueryWrapper<Order> q1=new QueryWrapper<>();
        q1.select("order_id","user_id","user_phone","order_status","order_real_price","create_time");
        q1.eq("order_id",orderId);
        Order order = orderService.getOne(q1);
        if(!order.getUserId().equals(userId))
            return ResponseFormat.failure("非法操作");
        boolean b = lockOrder(userId);
        if(!b)
            return ResponseFormat.failure("订单操作频繁");
        Integer status=order.getOrderStatus();
        if(!status.equals(OrderEnum.ING.getCode()))
            return ResponseFormat.ok("非等待送达订单,不可确认收货");
        orderService.confirmGoods(order);
        return ResponseFormat.ok("订单完成成功");
    }

    @GetMapping("/cancel")
    @ApiOperation("用户希望取消订单(只有货到付款的订单或者待支付的订单可以取消)")
    public ResponseFormat cancelOrder(@RequestParam(value = "orderId")String orderId) throws IOException {

        Integer userId=SecurityUnit.getUserId();

        QueryWrapper<Order> q1=new QueryWrapper<>();
        q1.select("order_id","user_id","order_status");
        q1.eq("order_id",orderId);
        Order order = orderService.getOne(q1);

        Integer status=order.getOrderStatus();
        if(!status.equals(OrderEnum.FACETO.getCode())//非货到付款订单
                &&!status.equals(OrderEnum.NOPAY.getCode())){//非等待支付订单
            //非货到付款订单货非待支付订单 不可以进行取消订单
            return ResponseFormat.failure("当前状态不支持此操作");
        }

        if(!order.getUserId().equals(userId))
            return ResponseFormat.failure("非法操作");

        boolean b = lockOrder(userId);
        if(!b)
            return ResponseFormat.failure("订单操作频繁");

        if(order.getOrderStatus().equals(OrderEnum.NOPAY.getCode())){

            //待支付状态可以直接取消,记得还优惠券+砍价商品
            order.setOrderStatus(OrderEnum.CANCEL.getCode());
            orderService.updateById(order);
            //返还(队列不会重复处理)
            orderService.cancelOrder(orderId);
            return ResponseFormat.ok("订单已取消");
        }
        if(order.getOrderStatus().equals(OrderEnum.ING.getCode())){//等待送达是微信支付后的状态
            return ResponseFormat.failure("已微信付款的订单请申请退款");
        }
        if(order.getOrderStatus().equals(OrderEnum.FACETO.getCode())){
            //货到付款订单才可以是取消订单,而微信支付订单是申请退款
            //等待送达订单需要老板确认
            //改变状态
            order.setOrderStatus(OrderEnum.CANCELING.getCode());
            orderService.updateById(order);

            WebSocketServer.sendCancelOrderTip();

            return ResponseFormat.ok("订单已申请取消");
        }
        return ResponseFormat.failure("当前状态不可以取消");
    }

    @GetMapping("/rollbackCancel")
    @ApiOperation("撤回申请取消订单(恢复成货到付款状态)")
    public ResponseFormat rollbackCancel(@RequestParam(value = "orderId")String orderId){
        Integer userId = SecurityUnit.getUserId();

        QueryWrapper<Order> q1=new QueryWrapper<>();
        q1.select("user_id","order_status");
        q1.eq("order_id",orderId);
        Order order = orderService.getOne(q1);
        if(!StringUtils.equals(userId.toString(),order.getUserId().toString())){
            return ResponseFormat.failure("禁止横向越权");
        }

        boolean b = lockOrder(userId);
        if(!b)
            return ResponseFormat.failure("订单操作频繁");

        Integer status=order.getOrderStatus();
        if(!OrderEnum.CANCELING.getCode().equals(status)){
            return ResponseFormat.failure("非取消中状态,不可撤回");
        }

        UpdateWrapper<Order> u1=new UpdateWrapper<>();
        u1.eq("order_status",OrderEnum.CANCELING.getCode())//必须是取消中状态
                .eq("order_id",orderId);
        u1.set("order_status",OrderEnum.FACETO.getCode());//改为货到付款状态
        //进行撤回
        boolean update = orderService.update(u1);
        if(!update){
            return ResponseFormat.failure("系统繁忙");
        }
        return ResponseFormat.ok("撤回取消订单成功");
    }

    @GetMapping("/returnOrder")
    @ApiOperation("用户申请退款(等待送达或者已完成的订单才可以申请退款)")
    public ResponseFormat returnOrder(@RequestParam(value = "orderId")String orderId){
        Integer userId=SecurityUnit.getUserId();

        QueryWrapper<Order> q1=new QueryWrapper<>();
        q1.eq("order_id",orderId);
        q1.select("order_id","user_id","order_status");
        Order order = orderService.getOne(q1);
        if(!userId.equals(order.getUserId()))
            return ResponseFormat.failure("非法操作");
        boolean b = lockOrder(userId);
        if(!b)
            return ResponseFormat.failure("订单操作频繁");
        Integer status=order.getOrderStatus();
        //非微信支付和非等待送达不支持申请
        if(!status.equals(OrderEnum.ING.getCode())&&!status.equals(OrderEnum.OK.getCode()))
            return ResponseFormat.failure("当前状态不支持此操作");
        //保存当前状态3天,方便后面取消时操作
        stringRedisTemplate.opsForValue().set("orderStatus:"+orderId,order.getOrderStatus().toString(),
                3,TimeUnit.DAYS);
        order.setOrderStatus(OrderEnum.REFUNDING.getCode());//改为退款中
        orderService.updateById(order);//修改为退款中
        try {
            WebSocketServer.sendReturnOrderTip();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ResponseFormat.ok("已申请退款");
    }

    @GetMapping("/rollbackReturn")
    @ApiOperation("撤回申请退款(恢复成待送达或已完成)")
    public ResponseFormat rollbackReturn(@RequestParam(value = "orderId")String orderId){

        Integer userId = SecurityUnit.getUserId();

        QueryWrapper<Order> q1=new QueryWrapper<>();
        q1.select("user_id","order_status");
        q1.eq("order_id",orderId);
        Order order = orderService.getOne(q1);
        if(!order.getUserId().equals(userId))
            return ResponseFormat.failure("禁止横向越权");
        boolean b = lockOrder(userId);
        if(!b)
            return ResponseFormat.failure("订单操作频繁");
        //非申请退款中状态
        if(!order.getOrderStatus().equals(OrderEnum.REFUNDING.getCode()))
            return ResponseFormat.failure("非申请退款状态,不可操作");
        //如何得知之前的状态呢? 等待送达 or 已完成
        String oldStatus = stringRedisTemplate.opsForValue().get("orderStatus:" + orderId);
        Integer status=OrderEnum.OK.getCode();//默认是已完成状态
        if(oldStatus!=null)
            status=Integer.parseInt(oldStatus);
        //撤回申请退款
        UpdateWrapper<Order> u1=new UpdateWrapper<>();
        u1.eq("order_status",OrderEnum.REFUNDING.getCode())//必须是退款中状态
                .eq("order_id",orderId);
        u1.set("order_status",status);//改为对应的状态
        //进行撤回
        boolean update = orderService.update(u1);
        if(!update){
            return ResponseFormat.failure("系统繁忙");
        }
        stringRedisTemplate.delete("orderStatus:"+orderId);//删除缓存
        return ResponseFormat.ok("撤销退款成功");
    }

    private List<OrderListVo> getOrderListVo(OrderEnum orderEnum,Integer userId){

        QueryWrapper<Order> q1=new QueryWrapper<>();
        q1.select("order_id","order_real_price","order_status","create_time");
        q1.eq("user_id",userId);
        q1.eq("order_status",orderEnum.getCode());
        List<Order> list = orderService.list(q1);

        if(list.size()==0)//没有此状态的订单
            return new ArrayList<OrderListVo>();

        return getOrderListVo2(list);//这里有order2
    }

    //获取更详细的订单(商品图片+商品id)
    private List<OrderListVo> getOrderListVo2(List<Order> list){
        List<OrderListVo> listVos=new ArrayList<>(list.size());
        list.forEach(l->{
            QueryWrapper<OrderItem> q2=new QueryWrapper<>();
            q2.select("product_id");
            q2.eq("order_id",l.getOrderId());
            List<OrderItem> itemList = orderItemService.list(q2);
            Set<Integer> set=itemList.stream().map(OrderItem::getProductId).collect(Collectors.toSet());
            List<Product> productList = productService.getImageById(set);
            OrderListVo orderListVo=new OrderListVo();
            orderListVo.setCreateDate(l.getCreateTime());
            orderListVo.setOrderId(l.getOrderId());
            orderListVo.setStatus(l.getOrderStatus());
            orderListVo.setProductList(productList);
            orderListVo.setSum(l.getOrderRealPrice());
            listVos.add(orderListVo);
        });

        return listVos;
    }

    private boolean lockOrder(Integer userId){
        //这里才需要进行锁
        Boolean flag = stringRedisTemplate.hasKey(OrderCommon.doOrderLock + userId);
        if(flag)//存在订单锁
            return false;
        //上锁
        stringRedisTemplate.opsForValue().set(OrderCommon.doOrderLock+userId,"1",10,TimeUnit.SECONDS);
        return true;
    }

}
